package com.chenfan.finance.service.impl;

import cn.afterturn.easypoi.csv.entity.CsvImportParams;
import cn.afterturn.easypoi.csv.imports.CsvImportService;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.sax.handler.RowHandler;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.chenfan.finance.dao.*;
import com.chenfan.finance.model.*;
import com.chenfan.finance.model.dto.AlipayOriginExcelDTO;
import com.chenfan.finance.model.dto.TocChargeQuery;
import com.chenfan.finance.utils.BatchInsertUtil;
import com.chenfan.finance.utils.BeanUtilCopy;
import com.chenfan.finance.utils.TimeFormatUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author liran
 */
@Slf4j
@Service
public class TocImportDataService {
    @Autowired
    private TocAlipayMappingIncomeMapper incomeMapper;
    @Autowired
    private ReferenceTableMapper referenceTableMapper;
    @Autowired
    private TocU8HeaderMapper tocU8HederMapper;
    @Autowired
    private TocU8DetailMapper tocU8DetailMapper;
    @Autowired
    private TocChargeMapper tocChargeMapper;


    public List<Map<String, String>> impotData(MultipartFile[] files, MultipartFile[] lasts) throws Exception {
        LinkedList<Map<String, String>> ms = new LinkedList<>();
        long startTime = System.currentTimeMillis();
        int all = 0;
        for (MultipartFile file : files) {
            if (file == null) {
                continue;
            }
            all = all + parseCVSandInsert(file, 4, ms);

        }
        for (MultipartFile file : lasts) {
            if (file == null) {
                continue;
            }
            all = all + parseCVSandInsert(file, 0, ms);
        }
        long endTime = System.currentTimeMillis();
        String msg = "插入总数: " + all + " ，耗时： " + (endTime - startTime) / 1000 + " s.";
        ms.addFirst(addMsg(msg, "本次插入"));
        return ms;
    }

    public int parseCVSandInsert(MultipartFile file, int setTitleRows, List<Map<String, String>> ms) throws IOException {
        List<AlipayOriginExcelDTO> fileModels = importCvs(file, AlipayOriginExcelDTO.class, setTitleRows);

        List<TocAlipayOrigin> alipays = new ArrayList<>(fileModels.size());
        for (AlipayOriginExcelDTO fileModel : fileModels) {
            TocAlipayOrigin alipayOrigin = convertToModel(fileModel);
            alipays.add(alipayOrigin);
        }
        long startTime = System.currentTimeMillis();
        int result = BatchInsertUtil.batchInsertTask(alipays, TocAlipayOriginMapper.class, "insertList");
        long endTime = System.currentTimeMillis();
        String msg = "插入总数: " + result + " ，耗时： " + (endTime - startTime) / 1000 + " s.";
        ms.add(addMsg(msg, file.getOriginalFilename()));
        return result;
    }

    private Map<String, String> addMsg(String msg, String name) {
        Map<String, String> d = new HashMap<>(4);
        d.put(name, msg);
        return d;
    }


    private List<AlipayOriginExcelDTO> importCvs(MultipartFile file, Class<AlipayOriginExcelDTO> clazz, int setTitleRows) throws IOException {
        CsvImportParams params = new CsvImportParams(CsvImportParams.GBK);
        params.setTitleRows(setTitleRows);
        params.setKeyIndex(5);

        return new CsvImportService().readExcel(file.getInputStream(), clazz, params, null);
    }


    private List<AlipayOriginExcelDTO> importExcel(MultipartFile file, int i, int i1, Class<AlipayOriginExcelDTO> alipayOriginExcelDTOClass) throws IOException {
        ExcelUtil.readBySax(file.getInputStream(), 1, new RowHandler() {
            @Override
            public void handle(int sheetIndex, int rowIndex, List<Object> rowList) {
                System.out.println(sheetIndex + "_" + rowIndex + JSONObject.toJSONString(rowList));
            }
        });
        return new LinkedList<>();
    }

    private TocAlipayOrigin convertToModel(AlipayOriginExcelDTO fileModel) {
        try {
            TocAlipayOrigin alipayOrigin = BeanUtilCopy.copyPropertiesIgnoreType(fileModel, TocAlipayOrigin.class);
            return alipayOrigin;
        } catch (Exception e) {
            log.error(fileModel.toString(), e);

        }
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    public void sumMonthData(String shop) {
        LocalDateTime now = LocalDateTime.now().plusMonths(-2);
        int brand = 2;
        sumMonthData(brand, shop, now);
    }

    @Transactional(rollbackFor = Exception.class)
    public void sumMonthData(int brand, String shop, LocalDateTime now) {

        LocalDateTime start = LocalDateTime.of(LocalDate.from(now), LocalTime.MIN).with(TemporalAdjusters.firstDayOfMonth());
        LocalDateTime end = LocalDateTime.of(LocalDate.from(start.plusDays(7)), LocalTime.MAX);
        List<TocAlipayMappingIncome> incomeList = incomeMapper.getInputList(start, end, Integer.parseInt(shop));
        List<TocAlipayMappingExpend> expendList = incomeMapper.getOutputList(start, end, Integer.parseInt(shop));
        int weekOfMonth = 1;
        TocU8Header in = insertHeaderIn(incomeList, brand, weekOfMonth);
        TocU8Header out = insertHeaderOut(expendList, brand, weekOfMonth);
        insertTocU8(in);
        insertTocU8(out);


    }

    private void updatein(TocU8Header in) {
        tocU8HederMapper.updateById(in);
    }

    private void insertTocU8(TocU8Header heder) {
        tocU8HederMapper.insert(heder);
        insertDetail(heder.getSkuInfos());
    }


    private void setDbVt(TocU8Header in) {
        // 301传 71   315的库 传87
        if (in.getU8db().contains("315")) {
            in.setVtId("87");
        }
        if (in.getU8db().contains("301")) {
            in.setVtId("71");
        }
    }


    private TocU8Header insertHeaderOut(List<TocAlipayMappingExpend> expendList, int brand, int week) {
        if (expendList.size() < 1) {
            return null;
        }
        TocAlipayMappingExpend d = expendList.get(0);
        TocU8Header heder = new TocU8Header();
        heder.setMappingId(d.getFinanceNo());
        heder.setDaozhangt(TimeFormatUtil.localDateTimeToString(d.getReceivedDate(), "yyyy-MM-dd HH:mm:ss"));
        int year = d.getReceivedDate().getYear();
        int month = d.getReceivedDate().getMonthValue();
        heder.setType(1);
        heder.setMonth("" + year + month);
        heder.setBrandId(brand);
        heder.setWeeknOfMonth(week);
        // tocU8HederMapper.insert(heder);
        List<TocU8Detail> details = new ArrayList<>();
        for (TocAlipayMappingExpend c : expendList) {
            if (StringUtils.isBlank(c.getSkuCode())) {
                continue;
            }
            details.add(convertOut(c, heder));
        }
        // insertDetail(details);
        heder.setSkuInfos(details);
        return heder;
    }

    private TocU8Detail convertOut(TocAlipayMappingExpend c, TocU8Header heder) {
        TocU8Detail detail = new TocU8Detail();
        detail.setDetailId(c.getId() + "");
        detail.setSpuName(c.getGoodsName());
        detail.setSpuCode(c.getSpuCode());
        detail.setSkuName(c.getGoodsName());
        detail.setSkuCode(c.getSkuCode());
        detail.setSkuPrice(c.getExpenseAmt());
        detail.setSkuCount(new BigDecimal(c.getRefundQty()));
        detail.setTotalMoney(new BigDecimal(c.getRefundQty()).multiply(c.getExpenseAmt()));
        detail.setDaozhangt(heder.getDaozhangt());
        detail.setMappingId(heder.getMappingId());
        return detail;
    }

    /**
     * @param incomeList
     * @param
     */
    private TocU8Header insertHeaderIn(List<TocAlipayMappingIncome> incomeList, int brand, int week) {
        if (incomeList.size() < 1) {
            return null;
        }
        TocAlipayMappingIncome d = incomeList.get(0);
        TocU8Header heder = new TocU8Header();
        heder.setMappingId(d.getFinanceNo());
        heder.setDaozhangt(TimeFormatUtil.localDateTimeToString(d.getReceivedDate(), "yyyy-MM-dd HH:mm:ss"));
        int year = d.getReceivedDate().getYear();
        int month = d.getReceivedDate().getMonthValue();
        heder.setType(0);
        heder.setMonth("" + year + month);
        heder.setBrandId(brand);
        heder.setWeeknOfMonth(week);

        List<TocU8Detail> details = new ArrayList<>();
        for (TocAlipayMappingIncome c : incomeList) {
            if (StringUtils.isBlank(c.getSkuCode())) {
                continue;
            }
            details.add(convert1(c, heder));
        }
        //  insertDetail(details);
        heder.setSkuInfos(details);
        return heder;
    }

    private void insertDetail(List<TocU8Detail> details) {
        for (TocU8Detail detail : details) {
            tocU8DetailMapper.insert(detail);
        }
    }

    /**
     * tradeOrderId  订单子订单id
     * tid	 原始订单号
     * sku	 sku编码
     * spu
     * skuName
     * huopin	 货品名称
     * <p>
     * shuliang	 数量
     * <p>
     * danjia	 单价
     * <p>
     * skuPaid	 sku支付
     * <p>
     * daozhangt	 到账时间
     * <p>
     * zidingdan	 子订单号
     * <p>
     * alipay	 支付宝订单号
     *
     * @param c
     * @param heder
     * @return
     */
    private TocU8Detail convert1(TocAlipayMappingIncome c, TocU8Header heder) {
        TocU8Detail detail = new TocU8Detail();
        detail.setDetailId(c.getId() + "");
        detail.setSpuName(c.getGoodsName());
        detail.setSpuCode(c.getSpuCode());
        detail.setSkuName(c.getGoodsName());
        detail.setSkuCode(c.getSkuCode());
        detail.setSkuPrice(c.getTotalAmtAfterShare());
        detail.setSkuCount(new BigDecimal(c.getConsignQty()));
        detail.setTotalMoney(new BigDecimal(c.getConsignQty()).multiply(c.getTotalAmtAfterShare()));
        detail.setDaozhangt(heder.getDaozhangt());
        detail.setMappingId(heder.getMappingId());
        return detail;
    }


    public String reference(int t) {
        LocalDateTime now = LocalDateTime.now().plusMonths(-2);
        LocalDateTime start = LocalDateTime.of(LocalDate.from(now), LocalTime.MIN).with(TemporalAdjusters.firstDayOfMonth());
        LocalDateTime end = LocalDateTime.of(LocalDate.from(now), LocalTime.MAX).with(TemporalAdjusters.lastDayOfMonth());
        long startTime = System.currentTimeMillis();
        int result = 0;
        int pageNum = 1;
        while (pageNum > 0) {
            if (t == 1) {
                PageInfo<ReferenceTable> byPage = getByPage(start, end, pageNum, t);
                result = result + doInsertReference(byPage.getList(), t);
                pageNum = byPage.getNextPage();
                if (!byPage.isHasNextPage()) {
                    break;
                }
            } else if (t == 2) {
                PageInfo<ReferenceTable> byPage = getByPage(start, end, pageNum, t);
                result = result + doInsertReference(byPage.getList(), t);
                pageNum = byPage.getNextPage();
                if (!byPage.isHasNextPage()) {
                    break;
                }
            } else if (t == 3) {
                PageInfo<ReferenceTable> byPage = getByPage(start, end, pageNum, t);
                result = result + doInsertReference(byPage.getList(), t);
                pageNum = byPage.getNextPage();
                if (!byPage.isHasNextPage()) {
                    break;
                }
            }
        }
        long endTime = System.currentTimeMillis();
        return "插入总数: " + result + " ，耗时： " + (endTime - startTime) / 1000 + " s.";
    }

    private PageInfo<ReferenceTable> getByPage(LocalDateTime start, LocalDateTime end, int pageNum, int t) {
        if (t == 1) {
            PageHelper.startPage(pageNum, 10000);
            List<ReferenceTable> tables = referenceTableMapper.getTargetDeliverTableIds(start, end);
            return new PageInfo<>(tables);
        } else if (t == 2) {
            PageHelper.startPage(pageNum, 10000);
            List<ReferenceTable> tables = referenceTableMapper.getTargetOrderTableIds(start, end);
            return new PageInfo<>(tables);
        } else if (t == 3) {
            PageHelper.startPage(pageNum, 10000);
            List<ReferenceTable> tables = referenceTableMapper.getTargetStockInTableIds(start, end);
            return new PageInfo<>(tables);
        }
        return null;
    }

    private int doInsertReference(List<ReferenceTable> tables, int t) {
        tables = tables.stream().filter(a -> StringUtils.isNotBlank(a.getTid())).collect(Collectors.toList());
        List<ReferenceTable> tablesSp = new LinkedList<>();
        for (ReferenceTable table : tables) {
            table.setTableType(t);
            if (table.getTid().contains(",")) {
                String[] split = table.getTid().split(",");
                tablesSp.addAll(createTable(split, table));
            }
        }
        tables.addAll(tablesSp);
        return BatchInsertUtil.batchInsertTask(tables, ReferenceTableMapper.class, "insertList");
    }

    private Collection<? extends ReferenceTable> createTable(String[] split, ReferenceTable table) {
        LinkedList<ReferenceTable> tables = new LinkedList<>();
        for (String s : split) {
            if (StringUtils.isBlank(s)) {
                continue;
            }
            ReferenceTable t = new ReferenceTable();
            t.setId(table.getId());
            t.setTid(s);
            t.setTableType(table.getTableType());
            t.setTaskYearMonth(table.getTaskYearMonth());
            tables.add(t);
        }
        if (tables.size() > 0) {
            ReferenceTable last = tables.removeLast();
            table.setId(last.getId());
            table.setTid(last.getTid());
            table.setTableType(last.getTableType());
            table.setTaskYearMonth(last.getTaskYearMonth());
        }
        return tables;
    }

    /**
     * @param t     table表   2  toc_sales_order_header  ，1  toc_sales_deliver_header 3 toc_stockin_order_header
     * @param start
     * @param end
     * @param tid
     * @return
     */
    public List<ReferenceTable> getReferenceIdByTid(int t, LocalDateTime start, LocalDateTime end, Object... tid) {
        return referenceTableMapper.selectList(Wrappers.lambdaQuery(ReferenceTable.class).between(ReferenceTable::getTaskYearMonth, start, end)
                .in(ReferenceTable::getTid, tid).eq(ReferenceTable::getTableType, t));
    }

    /***
     * 创建费用
     * @param query
     */
    public void saveTocCharge(TocChargeQuery query) {
        setDefaultTime(query);
        List<TocCharge> tocChargesIn = incomeMapper.chargeListIn(query);
        List<TocCharge> tocChargesOut = incomeMapper.chargeListOut(query);
        insertTocCharge(tocChargesIn);
        insertTocCharge(tocChargesOut);
    }

    private void insertTocCharge(List<TocCharge> tocChargesIn) {
        for (TocCharge tocCharge : tocChargesIn) {
            tocChargeMapper.insert(tocCharge);
        }
    }

    /**
     * 分页查询销售订单费用列表
     *
     * @param query
     * @return
     */
    public PageInfo<TocCharge> tocChargePageInfo(TocChargeQuery query) {
        setDefaultTime(query);
        PageHelper.startPage(query.getPageNum(), query.getPageSize());
        LambdaQueryWrapper<TocCharge> queryWrapper = Wrappers.lambdaQuery(TocCharge.class);
        queryWrapper.between(TocCharge::getReceivedDate, query.getStart(), query.getEnd());
        if (StringUtils.isNotBlank(query.getSkuCode())) {
            queryWrapper.eq(TocCharge::getChargeSourceDetailCode, query.getSkuCode());
        }
        List<TocCharge> tocCharges = tocChargeMapper.selectList(queryWrapper);
        return new PageInfo<>(tocCharges);
    }

    private void setDefaultTime(TocChargeQuery query) {
        if (query.getStart() == null) {
            LocalDateTime be = LocalDateTime.of(LocalDate.now().plusMonths(-1), LocalTime.MIN).with(TemporalAdjusters.firstDayOfMonth());
            LocalDateTime en = LocalDateTime.of(LocalDate.now().plusMonths(-1), LocalTime.MAX).with(TemporalAdjusters.lastDayOfMonth());
            query.setStart(be);
            query.setEnd(en);
            return;
        }
        if (query.getStart() != null) {
            query.setStart(LocalDateTime.of(query.getStart().toLocalDate(), LocalTime.MIN));
        }
        if (query.getEnd() != null) {
            query.setEnd(LocalDateTime.of(query.getEnd().toLocalDate(), LocalTime.MAX));
        }
    }

}
